/* Archive Extractor
 * Copyright 2008-2009 Matthew Hoops
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * $URL: http://archive-extractor.googlecode.com/svn/trunk/gob.cpp $
 * $Id: gob.cpp 2 2009-03-23 01:29:43Z clone2727 $
 *
 */

#include "gob.h"

#define BUFSIZE 16384

GobArchive::GobArchive() : StandardArchive() {
}

std::vector<const char*> GobArchive::getArchiveExtensions() {
	std::vector<const char*> exList;
	exList.push_back("gob"); // Dark Forces, Jedi Knight, Infernal Machine
	exList.push_back("goo"); // Mysteries of the Sith
	return exList;
}

enum GobVersion {
	kVersionJedi = 'GOB\x0a',
	kVersionSith = 'GOB '
};

int GobArchive::detect(FILE* file) {
	uint32 tag = readUint32BE(file);
	if (tag == kVersionJedi || tag == kVersionSith)
		return 100;
	return 0;
}

struct GobEntry {
	uint32 offset;
	uint32 size;
	char filename[128]; // Jedi Length == 13, Sith Length == 128
};

bool GobArchive::extractFiles(FILE* file) {
	uint32 tag = readUint32BE(file);
	
	if (tag == kVersionSith)
		readUint32LE(file); // Skip unknown
	
	// Get to the entry table
	fseek(file, readUint32LE(file), SEEK_SET);
	
	// Read in the entry table
	uint32 entryCount = readUint32LE(file);
	GobEntry *gobEntries = new GobEntry[entryCount];
	for (uint32 i = 0; i < entryCount; i++) {
		gobEntries[i].offset = readUint32LE(file);
		gobEntries[i].size = readUint32LE(file);
		if (tag == kVersionJedi)
			fread(gobEntries[i].filename, 1, 13, file);
		else
			fread(gobEntries[i].filename, 1, 128, file);
	}
	
	// Now let's go extract the files
	byte *data = (byte *)malloc(BUFSIZE);
	for (uint32 i = 0; i < entryCount; i++) {
		printf ("Extracting file \'%s\'...\n", gobEntries[i].filename);
	
		FILE *output = fopen(gobEntries[i].filename, "wb");
		if (!output) {
			printf ("Could not open file for output!\n");
			return false;
		}
		
		fseek(file, gobEntries[i].offset, SEEK_SET);
		
		while (gobEntries[i].size) {
			uint32 calcSize = BUFSIZE;
			if (gobEntries[i].size < BUFSIZE)
				calcSize = gobEntries[i].size;
			gobEntries[i].size -= calcSize;
			
			fread(data, 1, calcSize, file);
			fwrite(data, 1, calcSize, output);
		}
		
		fflush(output);
		fclose(output);
	}	
	
	free(data);
	delete[] gobEntries;
	return true;
}
